﻿#include <QApplication>
#include <QRect>
#include <QGridLayout>
#include <QDialog>
#include <QTextEdit>
#include <QLineEdit>
#include <QLabel>
#include <QPushButton>
#include "QFlowChart.h"
#include "QBlock.h"
#include <QMouseEvent>
#include "ParallelBlock.h"
#include "IPluginOperator.h"


namespace CVV
{

namespace FlowChart
{


QFlowChart::QFlowChart(QMenu *blockMenu, QWidget *parent)
    : QWidget(parent)
    , m_pRoot(new QBlock(blockMenu))
    , m_pFlowChartMenu(blockMenu)
{
    qRegisterMetaType<QHash<QString, QList<CVV::Interface::FlowCellParam>>>("QHash<QString, QList<CVV::Interface::FlowCellParam>>");
    root()->setFlowChart(this); //根节点传入流程图指针
    clear();
    setZoom(1);
}

QFlowChart::~QFlowChart()
{
    clear();
}

QDomDocument QFlowChart::document() const
{
    QDomDocument doc("CVV");
    QDomElement r = root()->xmlNode(doc);
    doc.appendChild(r);
    return doc;
}


QDomDocument QFlowChart::getCurBlockDocument(QBlock *curBlock)
{
    QDomDocument doc("CVV");
    QDomElement r = curBlock->xmlNode(doc);
    doc.appendChild(r);
    return doc;
}


QInsertionPoint QFlowChart::targetPoint() const
{
    return m_targetPoint;
}

void QFlowChart::setFlowFilePath(const QString &path)
{
    m_flowFilePath = path;
}

QString QFlowChart::getFlowFilePath() const
{
    return m_flowFilePath;
}

int QFlowChart::checkParallelBlock(QMouseEvent *evt, int &branchId)
{
    int ret = 0;
    if(m_pActiveBlock)
    {
        m_pActiveBlock->m_bSelectAll = false;
    }

    m_pActiveBlock = nullptr;

    QBlock *block = root()->blockAt(evt->x(), evt->y());

    if (block)
    {
        if (block->isActive() && ((evt->modifiers() & Qt::ControlModifier) != 0))
        {
            if(activeBlock()->m_pParentBlock)
            {
                m_pActiveBlock = activeBlock()->m_pParentBlock;
            }
            else
            {
                m_pActiveBlock = block;
            }
            m_pActiveBlock->m_bSelectAll = true;
        }
        else
        {
            if(block->m_pParentBlock && block->m_bIsBranch)
            {
                m_pActiveBlock = block->m_pParentBlock;
            }
            else
            {
                m_pActiveBlock = block;
            }
            m_pActiveBlock->m_bSelectAll = true;
        }

    }

    if(m_pActiveBlock)
    {
        bool isParallel = m_pActiveBlock->isBockType(QFlowEnum::BlockType::Parallel);
        if(isParallel)
        {
            //判断当前位置是否为分支标签
             QRect rect_position(static_cast<int>(m_pActiveBlock->m_dX), static_cast<int>(m_pActiveBlock->m_dY),
                                 static_cast<int>(m_pActiveBlock->m_dWidth), static_cast<int>(m_pActiveBlock->m_dHeight));
             QString tempStr = QString("");
             bool bExpand = m_pActiveBlock->getBlockExpandState();
             ParallelBlock paraBlock(tempStr, rect_position, m_pActiveBlock->zoom(), bExpand);
             paraBlock.setBranchItem(m_pActiveBlock->m_lstChildItems);
             QPointF pnt(evt->localPos());
             bool isBranchLabel = paraBlock.getBranchNum(pnt, branchId);
             if(isBranchLabel)
             {
                 ret = 1;
             }
        }
    }
    return  ret;
}

bool QFlowChart::checkContainerBlock(QMouseEvent *evt, bool &isExpand)
{
    if(m_pActiveBlock)
    {
        m_pActiveBlock->m_bSelectAll = false;
    }

    m_pActiveBlock = nullptr;

    QBlock *block = root()->blockAt(evt->x(), evt->y());

    if (block)
    {
        if (block->isActive() && ((evt->modifiers() & Qt::ControlModifier) != 0))
        {
            if(activeBlock()->m_pParentBlock)
            {
                m_pActiveBlock = activeBlock()->m_pParentBlock;
            }
            else
            {
                m_pActiveBlock = block;
            }
            m_pActiveBlock->m_bSelectAll = true;
        }
        else
        {
            if(block->m_pParentBlock && block->m_bIsBranch)
            {
                m_pActiveBlock = block->m_pParentBlock;
            }
            else
            {
                m_pActiveBlock = block;
            }
            m_pActiveBlock->m_bSelectAll = true;
        }
    }

    if(m_pActiveBlock)
    {
        isExpand = m_pActiveBlock->getBlockExpandState();
//        判断平行分支
        bool isParallel = m_pActiveBlock->isBockType(QFlowEnum::BlockType::Parallel);
        if(isParallel)
        {
            if(isExpand)
            {
                //判断点击是否为中心位置
                QRect rect_position(static_cast<int>(m_pActiveBlock->m_dX), static_cast<int>(m_pActiveBlock->m_dY),
                                    static_cast<int>(m_pActiveBlock->m_dWidth), static_cast<int>(m_pActiveBlock->m_dHeight));
                QString tempStr = QString("");
                ParallelBlock paraBlock(tempStr, rect_position, m_pActiveBlock->zoom(), isExpand);
                paraBlock.setBranchItem(m_pActiveBlock->m_lstChildItems);
                QPointF pnt(evt->localPos());
                int branchId = -1;
                bool isBranchLabel = paraBlock.getBranchNum(pnt, branchId);
                if(!isBranchLabel)
                {
                    return true;
                }
            }
            else
            {
                return true;
            }
        }

//        判断条件判断
        bool isIf = m_pActiveBlock->isBockType(QFlowEnum::BlockType::IF);
        if(isIf)
        {
            return true;
        }
//        判断前置循环
        bool isWhile = m_pActiveBlock->isBockType(QFlowEnum::BlockType::Pre);
        if(isWhile)
        {
            return true;
        }

//        判断后置循环
        bool isUntil = m_pActiveBlock->isBockType(QFlowEnum::BlockType::Post);
        if(isUntil)
        {
            return true;
        }

        bool isFor = m_pActiveBlock->isBockType(QFlowEnum::BlockType::For);
        if(isFor)
        {
            return true;
        }
    }

    return false;
}

QBlock * QFlowChart::root() const
{
    return m_pRoot;
}

QBlock * QFlowChart::activeBlock() const
{
    return m_pActiveBlock;
}

QBlock * QFlowChart::getBlock(const QString &blockCode, const QString &cellId)
{
    for(auto rootblock  : this->root()->m_lstChildItems)
    {
        for(auto block : rootblock->m_lstChildItems)
        {
            QString pcode = block->m_hashAttributes.value("code");
            QString cId = block->m_hashAttributes.value("id");
            if(blockCode == pcode && cellId == cId)
            {
                return block;
            }
            QBlock *pBlock = getChildBlock(block, blockCode, cellId);
            if (pBlock)
            {
                return pBlock;
            }
        }
    }
    return nullptr;
}

QList<QPair<QBlock*, QString>> QFlowChart::getBlock(const QString &blockCode)
{
    QList<QPair<QBlock*, QString>> blockList = {};
    for(auto rootblock  : this->root()->m_lstChildItems)
    {
        for(auto block : rootblock->m_lstChildItems)
        {
            QString pcode = block->m_hashAttributes.value("code");
            QString cId = block->m_hashAttributes.value("id");
            if(blockCode == pcode )
            {
                blockList.push_back(QPair<QBlock*, QString>(block, cId));
            }
            else
            {
                QBlock *pBlock = getChildBlock(block, blockCode, cId);
                if(pBlock)
                   blockList.push_back(QPair<QBlock*, QString>(block, cId));
            }
        }
    }
    return blockList;
}

double QFlowChart::zoom() const
{
    return m_dZoom;
}

void QFlowChart::setZoom(const double aZoom)
{
    m_dZoom = aZoom;
    m_bIsScaled = true;
    realignObjects();
    if (status() == Insertion)
    {
        m_targetPoint = QInsertionPoint();
        regeneratePoints();
    }
    emit zoomChanged(aZoom);
}

int QFlowChart::status() const
{
    return m_iStatus;
}

void QFlowChart::setStatus(int aStatus)
{
    m_iStatus = aStatus;
    if (status() == Insertion)
    {
        setMouseTracking(true);
        regeneratePoints();
        this->m_iBlockNum++;
        qDebug()<<"m_iBlockNum:"<<this->m_iBlockNum;
        QWidget::update();

        m_bIsUpdateAerialView = true;
    }
    else
    {
        m_targetPoint = QInsertionPoint();
        setMouseTracking(false);
    }

    //当不是选择模式时
    if(status() != Selectable)
    {
        for(QBlock* &block:m_findTargetBlockLst)
        {
            if(!block) continue;
            block->m_bSelectAll = false;
            block->m_bCurFindActive = false;
            block->m_bFindActive = false;
        }
    }

    emit statusChanged();
    emit changed();

}

void QFlowChart::deleteBlock(QBlock *aBlock)
{
    if (aBlock == root())
    {
        for(int i = 0; i < aBlock->m_lstChildItems.size(); ++i)
        {
            aBlock->item(i)->clear();
        }
        realignObjects();
    }
    else if (aBlock->m_bIsBranch)
    {
        aBlock->clear();
        realignObjects();
    }
    else
    {
        delete aBlock;
        realignObjects();
    }

    // 更新所有节点前节点id
    if (root())
    {
        root()->updateAllNodePreId();
    }

    emit changed();
}

QInsertionPoint QFlowChart::getNearistPoint(int x, int y) const
{
    QInsertionPoint result;
    if (m_lstinsertionPoints.size() > 0)
    {
        result = m_lstinsertionPoints.at(0);
        double len = calcLength(result.point(), QPointF(x, y));
        for (int i = 0; i < m_lstinsertionPoints.size(); ++i)
        {
            QInsertionPoint ip = m_lstinsertionPoints.at(i);
            double tmp = calcLength(ip.point(), QPointF(x, y));
            if (tmp < len)
            {
                result = ip;
                len = tmp;
            }
        }
    }
    return result;
}

void QFlowChart::regeneratePoints()
{
    m_lstinsertionPoints.clear();
    if(root())
    {
        generatePoints(root());
    }
}

void QFlowChart::generatePoints(QBlock *aBlock)
{
    if(aBlock->m_bIsBranch)
    {
        bool bVisible = aBlock->getBlockVisible();
        bool bExpand = aBlock->getBlockExpandState();
        double x = aBlock->m_dX + aBlock->m_dWidth / 2.0;
        for (int i = 0; i < aBlock->m_lstChildItems.size(); ++i)
        {
            double y = aBlock->item(i)->m_dY;
            QInsertionPoint p;
            p.setBranch(aBlock);
            p.setPoint(QPointF(x, y));
            p.setIndex(i);
            p.setNeedDraw( bVisible && bExpand);
            m_lstinsertionPoints.append(p);
            generatePoints(aBlock->item(i));
        }

        QInsertionPoint p;
        p.setBranch(aBlock);
        p.setNeedDraw(bVisible);
        if(aBlock->m_lstChildItems.size() == 0)
        {
            p.setPoint(QPointF(x, aBlock->m_dY + aBlock->m_dHeight - aBlock->m_dHeight / 3));
        }
        else
        {
            p.setPoint(QPointF(x, aBlock->m_dY + aBlock->m_dHeight));
        }

        p.setIndex(aBlock->m_lstChildItems.size());
        m_lstinsertionPoints.append(p);
    }
    else
    {
        for (int i = 0; i < aBlock->m_lstChildItems.size(); ++i)
        {
            generatePoints(aBlock->item(i));
        }
    }
}

QString QFlowChart::buffer() const
{
    return m_strBuffer;
}


void QFlowChart::setBuffer(const QString & aBuffer)
{
    QDomDocument doc;
    if(doc.setContent(aBuffer, false))
    {
        m_strBuffer = aBuffer;
    }
    else
    {
        m_strBuffer = QString();
    }
}


void QFlowChart::setMultiInsert(bool aValue)
{
    m_bIsMultiInsert = aValue;
}

bool QFlowChart::multiInsert() const
{
    return m_bIsMultiInsert;
}

QFlowChartStyle QFlowChart::chartStyle() const
{
    return m_chartStyle;
}

void QFlowChart::setChartStyle(const QFlowChartStyle & aStyle)
{
    m_chartStyle = aStyle;
    emit changed();
    QWidget::update();
}

QString QFlowChart::toString()
{
    return document().toString(2);
}

bool QFlowChart::fromString(const QString & str)
{
    QDomDocument doc;
    if(doc.setContent(str, false))
    {
        root()->setXmlNode(doc.firstChildElement());
        realignObjects();
        emit changed();

        return true;
    }

    return false;
}

bool QFlowChart::canUndo() const
{
    return !m_undoStack.isEmpty();
}

bool QFlowChart::canRedo() const
{
    return !m_redoStack.isEmpty();
}

bool QFlowChart::canPaste() const
{
    QDomDocument doc;
    QClipboard *clp = QApplication::clipboard();
    QString aBuffer = clp->text();
    return doc.setContent(aBuffer, false);
}

void QFlowChart::undo()
{
    if (!m_undoStack.isEmpty())
    {
        QString state = toString();
        m_redoStack.push(state);
        state = m_undoStack.pop().toString();
        bool bRet = fromString(state);
        slotDelAllBlocksSelectState();
        if(m_findTargetBlockLst.size() > 0)
        {
            m_findTargetBlockLst.clear();
            emit sigFoundReset();
        }
        emit changed();
        if (bRet)
        {
            emit sigRedoUndo(state);
        }
    }
}

void QFlowChart::makeUndo()
{
    QString state = toString();
    m_undoStack.push(state);
    m_redoStack.clear();
    emit modified();
}

void QFlowChart::redo()
{
    if (!m_redoStack.isEmpty())
    {
        QString state = toString();
        m_undoStack.push(state);
        state = m_redoStack.pop().toString();
        bool bRet = fromString(state);
        slotDelAllBlocksSelectState();
        if(m_findTargetBlockLst.size() > 0)
        {
            m_findTargetBlockLst.clear();
            emit sigFoundReset();
        }
        emit changed();
        if (bRet)
        {
            emit sigRedoUndo(state);
        }
    }
}

void QFlowChart::makeChanged()
{
    emit changed();
}

void QFlowChart::makeBackwardCompatibility()
{
    if(root())
    {
        root()->makeBackwardCompatibility();
    }
}

QPixmap QFlowChart::getBackgroundPixmap() const
{
    return m_backgroundPixmap;
}

void QFlowChart::setBackgroundPixmap(const QPixmap &value)
{
    m_backgroundPixmap = value;
}

void QFlowChart::paintTo(QPainter *canvas)
{
    if (root())
    {
        //1.绘制流程图
        root()->paint(canvas);
        //2.绘制插入点
        if (status() == Insertion)
        {
            QFlowChartStyle st = chartStyle();
            QPen oldP =  canvas->pen();
            QColor col(0x12, 0x96, 0xdb);
            QPen pe(col);
            canvas->setPen(pe);
            canvas->setBrush(QBrush(st.normalBackground()));
            for (int i = 0; i < m_lstinsertionPoints.size(); ++i)
            {
                QInsertionPoint ip = m_lstinsertionPoints.at(i);
                if(!ip.needDraw()) continue;
                QPointF p = ip.point();
                canvas->drawEllipse(p, 4 * zoom(), 4 * zoom());
            }
            if (!targetPoint().isNull() && targetPoint().needDraw())
            {
                QPointF p = targetPoint().point();
                canvas->drawEllipse(p, 6 * zoom(), 6 * zoom());
            }
            canvas->setPen(oldP);
        }
    }
}

void QFlowChart::modifyParallel(QBlock *ablock, int num, bool bAdd, const QList<int>& lstDeleteIndex)
{
    makeUndo();

    ablock->modify(num, bAdd, lstDeleteIndex);

    realignObjects();
    regeneratePoints();
    if(m_pActiveBlock)
    {
        m_pActiveBlock->m_bSelectAll = false;
    }

    m_pActiveBlock = nullptr;

    emit changed();

    if (!multiInsert())
    {
        setStatus(Selectable);
    }
}

void QFlowChart::updateParallelBranchStatus(QBlock *block, const QList<int> &lstEnableIndex)
{
    if (!block)
    {
        return;
    }

    block->updateParallelBranchStatus(lstEnableIndex);
}

double QFlowChart::calcLength(const QPointF & p1, const QPointF & p2)
{
    return (p1.x() - p2.x()) * (p1.x() - p2.x()) + (p1.y() - p2.y()) * (p1.y() - p2.y());
}

void QFlowChart::drawBottomArrow(QPainter *canvas, const QPointF & aPoint, const QSizeF & aSize)
{
    QVector<QPointF> arrow;
    arrow << QPointF(aPoint.x() - aSize.width()/2.0, aPoint.y() - aSize.height())
          << aPoint
          << aPoint
          << QPointF(aPoint.x() + aSize.width()/2.0, aPoint.y() - aSize.height());

    canvas->drawLines(arrow);
}


void QFlowChart::drawRightArrow(QPainter *canvas, const QPointF & aPoint, const QSizeF & aSize)
{
    QVector<QPointF> arrow;
    arrow << QPointF(aPoint.x() - aSize.width(), aPoint.y() - aSize.height()/2);
    arrow << aPoint;
    arrow << aPoint;
    arrow << QPointF(aPoint.x() - aSize.width(), aPoint.y() + aSize.height()/2);

    canvas->drawLines(arrow);
}

void QFlowChart::setIsPaste(bool value)
{
    m_bIsPaste = value;
}

void QFlowChart::setCtrlEnable(bool value)
{
    m_ctrlEnable = value;
}

bool QFlowChart::getCtrlEnable()
{
    return m_ctrlEnable;
}

void QFlowChart::checkMultBlocksSelected(int &selectType)
{
    int ret = selectType;
    int count = root()->m_lstChildItems.size();
    if(count != 1) return;
    QBlock *block = root()->m_lstChildItems[0];
    int childCount = block->m_lstChildItems.size();
    int selectCount = 0;
    for(int i = 0; i < childCount; ++i)
    {
        QBlock* curBlock = block->m_lstChildItems[i];
        if(curBlock->m_bSelectAll)
        {
            ++selectCount;
        }
        else {
            int subCount = curBlock->m_lstChildItems.size();
            if(subCount > 0)
            {
                getSelectBlockNum(curBlock, selectCount);
            }
        }
    }
    if(selectCount > 1)
    {
        ret = Multiple;
    }
    selectType = ret;
}

void QFlowChart::getSelectBlockNum(QBlock *block, int &count)
{
    int childcount = block->m_lstChildItems.size();
    for(int i = 0 ; i < childcount; ++i)
    {
        QBlock *childBlock = block->m_lstChildItems[i];
        if(childBlock->m_bSelectAll)
        {
            ++count;
        }
        else {
            int subCount = childBlock->m_lstChildItems.size();
            if(subCount > 0)
            {
                getSelectBlockNum(childBlock, count);
            }
        }
    }
}

QList<QBlock *> QFlowChart::getSelectBlocks()
{
    QList<QBlock *> blockLst;
    QList<QBlock *> childBlockLst = root()->m_lstChildItems;
    for(QBlock *childBlock:childBlockLst)
    {
        if(nullptr == childBlock) continue;
        if(childBlock->m_bSelectAll)
        {
            blockLst.append(childBlock);
        }
        else {
            int count = childBlock->m_lstChildItems.size();
            if(count != 0)
            {
                addSelectSubBlocks(childBlock, blockLst);
            }
        }
    }

    return blockLst;
}

void QFlowChart::addSelectSubBlocks(QBlock *targetBlock, QList<QBlock *> &blockLst)
{
    QList<QBlock *> childBlockLst = targetBlock->m_lstChildItems;
    for (QBlock *childBlock:childBlockLst)
    {
        if(nullptr == childBlock) continue;
        if(childBlock->m_bSelectAll)
        {
            blockLst.append(childBlock);
        }
        else {
            int count = childBlock->m_lstChildItems.size();
            if(count != 0)
            {
                addSelectSubBlocks(childBlock, blockLst);
            }
        }
    }
}

void QFlowChart::updateFindTargetBlocks(int searchCode, QString &keyStr)
{
    for (auto curBlock:m_findTargetBlockLst)
    {
        curBlock->m_bSelectAll = false;
        curBlock->m_bCurFindActive = false;
        curBlock->m_bFindActive = false;
    }
    m_findTargetBlockLst.clear();

    if(!keyStr.isEmpty())
    {
        findBlocksByKeyWord(root(), keyStr, searchCode);
        emit sigFoundBlocksResult(m_findTargetBlockLst.size(), 1);
    }
    int curBlockX =0;
    int curBlockY =0;
    int curWidth = 0;
    int curHeight = 0;
    if(m_findTargetBlockLst.size() > 0)
    {
        m_findTargetBlockLst[0]->m_bCurFindActive = true;
        curBlockX = static_cast<int>(m_findTargetBlockLst[0]->m_dX);
        curBlockY = static_cast<int>(m_findTargetBlockLst[0]->m_dY);
        curWidth = static_cast<int>(m_findTargetBlockLst[0]->m_dWidth);
        curHeight = static_cast<int>(m_findTargetBlockLst[0]->m_dHeight);
    }
    //立即重绘
    repaint();

    if(m_findTargetBlockLst.size() > 0)
    {
        emit signalCurFoundBlockChanged(curBlockX, curBlockY, curWidth, curHeight);
    }
}

void QFlowChart::getTargetBlocksCount(int &Count)
{
    Count = m_findTargetBlockLst.size();
}

int QFlowChart::getFindTargetBlocksCount()
{
    return m_findTargetBlockLst.size();
}

void QFlowChart::searchBlockChanged(int val)
{
    int findCount = m_findTargetBlockLst.size();
    int index = 0;
    int targetIndex = -1;
    for(QBlock* curBlock:m_findTargetBlockLst)
    {
        if(!curBlock) continue;

        if(curBlock->m_bCurFindActive)
        {
            curBlock->m_bCurFindActive = false;
            if(val < 0)
            {
                targetIndex = index - 1;
            }
            else {
                targetIndex = index + 1;
            }
            break;
        }
        index ++;
    }
    if(findCount > 0)
    {
        if(targetIndex < 0)
        {
            targetIndex = 0;
        }
        else if (targetIndex >= findCount) {
            targetIndex = findCount - 1;
        }
        emit sigFoundBlocksResult(m_findTargetBlockLst.size(), targetIndex + 1);
        m_findTargetBlockLst[targetIndex]->m_bCurFindActive = true;
        int curWidth = static_cast<int>(m_findTargetBlockLst[targetIndex]->m_dWidth);
        int curHeight = static_cast<int>(m_findTargetBlockLst[targetIndex]->m_dHeight);
        int curBlockX = static_cast<int>(m_findTargetBlockLst[targetIndex]->m_dX);
        int curBlockY = static_cast<int>(m_findTargetBlockLst[targetIndex]->m_dY);
        //立即重绘
        repaint();
        emit signalCurFoundBlockChanged(curBlockX, curBlockY, curWidth, curHeight);
    }
}

void QFlowChart::detectUnreferencedCells()
{
//    static bool checkState = false;
//    if(!checkState && 0 == m_unReferencedIdLst.size())
//    {
        m_unReferencedIdLst.clear();
        m_cellReferencedMap.clear();
        QStringList allCurIdLst, allPreIdLst;
        updateBlocksReferenceStatus(root(), allCurIdLst, allPreIdLst);
        allCurIdLst = allCurIdLst.toSet().toList();
        allPreIdLst = allPreIdLst.toSet().toList();

        QStringList allCurCompareLst = allCurIdLst;
        for (auto preIdStr: allPreIdLst) {
            if(allCurIdLst.contains(preIdStr))
            {
                allCurIdLst.removeOne(preIdStr);
            }
        }
        QStringList referencedStrLst = m_cellReferencedMap.keys();
        for (auto reIdStr: referencedStrLst) {
            if(allCurCompareLst.contains(reIdStr))
            {
                allCurCompareLst.removeOne(reIdStr);
            }
        }
        allCurIdLst.append(allCurCompareLst);
        allCurIdLst = allCurIdLst.toSet().toList();
        m_unReferencedIdLst = allCurIdLst;
        repaint();
//        checkState = true;
//    }
//    else if (checkState && 0 != m_unReferencedIdLst.size()) {
//        m_unReferencedIdLst.clear();
//        m_cellReferencedMap.clear();
//        repaint();
//    }

}

void QFlowChart::detectSelectedReferenceCurCell()
{
    m_referencedIdLst.clear();
    if(nullptr == m_pActiveBlock) return;
    QString cellTargetStr = QString("%1.%2").arg(m_pActiveBlock->m_hashAttributes.value("code"))
            .arg(m_pActiveBlock->m_hashAttributes.value("id"));
    QString strTargetId = m_pActiveBlock->m_hashAttributes.value("id");
    updateBlocksReferenceCurBlock( root(), cellTargetStr);

    m_referencedIdLst.removeOne(strTargetId);
    m_referencedIdLst = m_referencedIdLst.toSet().toList();
    repaint();
}

void QFlowChart::setContainBlockCollapseOrExpand(bool expand)
{
    m_referencedIdLst.clear();
    if(nullptr == m_pActiveBlock) return;
    m_pActiveBlock->setBlockExpandState(expand);
    updateBlocksExpandState(m_pActiveBlock, expand);
    realignObjects();
    regeneratePoints();
    repaint();
}

QStringList QFlowChart::getUnReferencedIdLst()
{
    return m_unReferencedIdLst;
}

QStringList QFlowChart::getReferencedIdLst()
{
    return m_referencedIdLst;
}

void QFlowChart::SetUnReferencedIdLst(QStringList strLst)
{
    m_unReferencedIdLst.clear();
    m_unReferencedIdLst.append(strLst);
}

bool QFlowChart::isSubprocessFlow()
{
    if (m_pActiveBlock)
    {
        return m_pActiveBlock->isBockType(QFlowEnum::SubFlow);
    }

    return false;
}

QVariant QFlowChart::getActiveBlockParamValueByCode(const QString &code)
{
    if (m_pActiveBlock)
    {
        QList<Interface::FlowCellParam> lstParams = m_pActiveBlock->getPluginInfo();
        for (auto p : lstParams)
        {
            if (p.code() == code)
            {
                if (p.userTypeValue().isValid())
                {
                    return p.userTypeValue();
                }
                return p.value();
            }
        }
    }

    return QVariant();
}

QVariant QFlowChart::getActiveBlockParam(QString &pluginCode) const
{
    pluginCode.clear();
    if (m_pActiveBlock)
    {
        QList<Interface::FlowCellParam> lstParams = m_pActiveBlock->getPluginInfo();

        QString pluginId = m_pActiveBlock->m_hashAttributes.value("id");
        pluginCode = m_pActiveBlock->m_hashAttributes.value("code");
        QString strKey = QString("%1_%2").arg(m_pActiveBlock->m_hashAttributes.value("title")).arg(pluginId);

        for (auto &p : lstParams)
        {
            p.setPluginId(pluginId);
            p.setPluginCode(pluginCode);
        }
        QHash<QString, QList<CVV::Interface::FlowCellParam>> hashData;
        hashData.insert(strKey, lstParams);

        return QVariant::fromValue(hashData);
    }

    return QVariant();
}

QString QFlowChart::getActiveBlockId() const
{
    if (m_pActiveBlock)
    {
        return m_pActiveBlock->id();
    }

    return "";
}

void QFlowChart::setId(int id)
{
    m_id = id;
}

int QFlowChart::getId() const
{
    return m_id;
}

void QFlowChart::deleteSelectBlockLst(QList<QBlock *> &delBlockLst)
{
    makeUndo();
    for ( QBlock *delBlock:delBlockLst)
    {
        if(!delBlock) continue;
        delBlock->m_bSelectAll = false;
        QBlock *tmp = delBlock;

        if(delBlock == m_pActiveBlock)
        {
            m_pActiveBlock = nullptr;
        }

        if(m_findTargetBlockLst.contains(delBlock))
        {
            m_findTargetBlockLst.removeOne(delBlock);
        }

        delBlock = nullptr;
        deleteBlock(tmp);
    }
    emit changed();
}

void QFlowChart::updateBlockPreId()
{
    // 更新所有节点前节点id
    if (root())
    {
        root()->updateAllNodePreId();
    }
    realignObjects();
    regeneratePoints();
}

void QFlowChart::setCurParallelNum(int selectNum)
{
    m_parallelNum = selectNum;
}

int QFlowChart::getCurParallelNum()
{
    return  m_parallelNum;
}

void QFlowChart::setFlowChartMenuShowState(bool state)
{
    m_menuShow = state;
}

bool QFlowChart::getFlowChartMenuShowState()
{
    return m_menuShow;
}

void QFlowChart::resetBlockRunState()
{
    for(auto &rootblock  : root()->m_lstChildItems)
    {
        for(auto &block : rootblock->m_lstChildItems)
        {
            if (block)
            {
                if(block->m_hashAttributes.contains("state"))
                {
                   block->m_hashAttributes["state"] = "";
                   QString pluginCode= block->m_hashAttributes["code"];
                   QString cellId=block->m_hashAttributes["id"];
                   CVV::Interface::IPluginOperator::resetDialogParamRunState(pluginCode,QString::number(m_id),cellId);
                }
            }
            resetChildBlockRunState(block);
        }
    }
}

void QFlowChart::resetChildBlockRunState(QBlock *pBlock)
{
    if (!pBlock)
    {
        return;
    }

    for(auto &childBlock  : pBlock->m_lstChildItems)
    {
        if (childBlock)
        {
            if(childBlock->m_hashAttributes.contains("state"))
            {
               childBlock->m_hashAttributes["state"] = "";
               QString pluginCode= childBlock->m_hashAttributes["code"];
               QString cellId=childBlock->m_hashAttributes["id"];
               CVV::Interface::IPluginOperator::resetDialogParamRunState(pluginCode,QString::number(m_id),cellId);
            }
        }

        resetChildBlockRunState(childBlock);
    }
}

int QFlowChart::checkMeetSubProcessConditions()
{
    int match = 1;
    QList<QBlock*> lstSelectBlock = getSelectBlocks();
    if(lstSelectBlock.size() <= 1)
    {
        return 0;
    }
    QStringList preIdLst;
    QStringList idLst;
    for(auto block : lstSelectBlock)
    {
        idLst.append(block->m_strId);
        preIdLst.append(block->m_strPreId);
    }

    int count = 0;
    for(auto preId : preIdLst)
    {
        if(!idLst.contains(preId))
        {
            ++count;
        }
    }
    if(1==count)
    {
        match = 2;
    }
    return match;
}

QBlock *QFlowChart::getTargetBlockById(const QString id, bool isPre)
{
    QBlock* targetBlock = nullptr;

    for(auto rootblock  : root()->m_lstChildItems)
    {
        if(targetBlock) break;
        for(auto block : rootblock->m_lstChildItems)
        {
            if(!isPre && block->m_strId == id)
            {
                targetBlock = block;
            }
            else if(isPre && block->m_strPreId == id)
            {
                targetBlock = block;
            }
            else
            {
                findChildTargetBlockId(block, targetBlock, id, isPre);
            }
            if(targetBlock) break;
        }
    }
    return targetBlock;
}

void QFlowChart::findChildTargetBlockId(QBlock *ParentBlock, QBlock *&targetBlock, const QString id, bool isPre)
{
    for(auto block  : ParentBlock->m_lstChildItems)
    {
        if(!isPre && block->m_strId == id)
        {
            targetBlock = block;
        }
        else if(isPre && block->m_strPreId == id)
        {
            targetBlock = block;
        }
        else
        {
            findChildTargetBlockId(block, targetBlock, id, isPre);
        }
        if(targetBlock) break;
    }
}

bool QFlowChart::insertSubProcessBlockByPreId(QBlock* replaceBlock, QDomElement &ele)
{
    QBlock *parentBlock = replaceBlock->m_pParentBlock;

    if(parentBlock)
    {
        int insertIndex = -1;
        for(int i = 0; i < parentBlock->m_lstChildItems.size(); i++)
        {
            if( replaceBlock->m_strId == parentBlock->m_lstChildItems.at(i)->m_strId )
            {
                insertIndex = i;
                break;
            }
        }
        if(-1 == insertIndex) return false;
        m_iBlockNum++;
        makeUndo();
        QBlock *bl = parentBlock->insertXmlTree(insertIndex, ele);
        if(nullptr == bl) return false;
        bl->m_bSubProcess = false;
        if(m_pActiveBlock)
        {
            m_pActiveBlock->m_bSelectAll = false;
        }
        m_pActiveBlock = nullptr;

        emit changed();
        emit sigInsertNode(bl, m_bIsPaste);
        if (m_bIsPaste)
        {
            m_bIsPaste = false;
        }
    }
    return true;
}

void QFlowChart::updateCellResultMap(QMap<int, bool> resultMap)
{
    m_cellResultMap = resultMap;
    repaint();
}

int QFlowChart::getCellResultState(const int cellId)
{
    int iState = 0; // 无结果
    if(m_cellResultMap.contains(cellId))
    {
        bool bVal = m_cellResultMap.value(cellId);
        if(bVal)
        {
            iState = 1; // 失败
        }
        else
        {
            iState = -1; // 成功
        }
    }
    return iState;
}

void QFlowChart::slotSelectAll()
{
    m_pActiveBlock = root();
    m_pActiveBlock->m_bSelectAll = true;
    emit changed();
    QWidget::update();
}

void QFlowChart::slotDelAllBlocksSelectState()
{
    if(m_pActiveBlock)
    {
        if(!m_findTargetBlockLst.contains(m_pActiveBlock))
        {
            m_pActiveBlock->m_bSelectAll = false;
        }
    }

    m_pActiveBlock = nullptr;
    delCurBlockChildBlockSelectedState(root());
    emit changed();
    QWidget::update();
}

void QFlowChart::paintEvent(QPaintEvent *pEvent)
{
    QPainter canvas(this);
    pEvent->accept();
    canvas.setClipRect(pEvent->rect());
    canvas.setRenderHint(QPainter::Antialiasing, true);
    paintTo(&canvas);

    if (m_bIsUpdateAerialView && !m_bIsScaled)
    {
        m_bIsUpdateAerialView = false;
        emit sigUpdageAerialView();
    }

    if (m_bIsScaled)
    {
        m_bIsScaled = false;
        emit sigUpdateAerialScaled();
    }
}

void QFlowChart::mousePressEvent(QMouseEvent *pEvent)
{
    if((pEvent->modifiers() & Qt::ControlModifier) != 0)
    {
        setCtrlEnable(true);
    }
    else {
        setCtrlEnable(false);
    }
    if (status() == Selectable)
    {
        QBlock *block = root()->blockAt(pEvent->x(), pEvent->y());
        //判断是否按住ctrl
        if(getCtrlEnable())
        {
            if(block)
            {
                delCurBlockChildBlockSelectedState(block);
            }
        }
        else
        {
            slotDelAllBlocksSelectState();
        }

        if (block)
        {
            if (block->isActive() && ((pEvent->modifiers() & Qt::ControlModifier) != 0))
            {
                if(activeBlock()->m_pParentBlock)
                {
                    m_pActiveBlock = activeBlock()->m_pParentBlock;
                }
                else
                {
                    m_pActiveBlock = block;
                }
                m_pActiveBlock->m_bSelectAll = true;
            }
            else
            {
                if(block->m_pParentBlock && block->m_bIsBranch)
                {
                    m_pActiveBlock = block->m_pParentBlock;
                }
                else
                {
                    m_pActiveBlock = block;
                }
                m_pActiveBlock->m_bSelectAll = true;
            }

            if(getCtrlEnable())
            {
                QBlock *parentBlock = m_pActiveBlock->m_pParentBlock;
                updateParentBlockSelectedState(parentBlock);
                delCurBlockChildBlockSelectedState(m_pActiveBlock);
            }

            if(pEvent->button()==Qt::LeftButton && pEvent->modifiers() == Qt::NoModifier)
            {
                emit sigSelectBlock(block);
            }
            emit changed();
            update();
        }
    }
    else if(status() == Insertion)
    {
        QPoint mp = pEvent->pos();
        QInsertionPoint ip = getNearistPoint(mp.x(), mp.y());
        m_targetPoint = ip;
        QString buffNodeStr = buffer();
        if(!ip.isNull() && !buffNodeStr.isEmpty())
        {
            QDomDocument doc;
            if(doc.setContent(buffNodeStr, false))
            {
                QDomElement algorithm = doc.firstChildElement("algorithm");
                QString subFilePath = "";
                QString cellId = "";
                bool isSubProcess = checkInsertSubProcessNode(algorithm, subFilePath, cellId);
                if(isSubProcess)
                {
                    QString titleStr = "";
                    QString targetFilePath = "";
                    if(subFilePath.isEmpty())
                    {
                        //子流程创建容器
                        emit sigCreateSubProcess(targetFilePath, cellId);
                        if(targetFilePath.isEmpty())
                        {
                            if (!multiInsert())
                            {
                                setStatus(Selectable);
                                this->m_iBlockNum = cellId.toInt();
                            }
                            return;
                        }
                        QFileInfo targetFinfo(targetFilePath);
                        QString targetBaseName = targetFinfo.baseName().trimmed();
                        QString removeStr = cellId+"_";
                        titleStr = targetBaseName.remove(removeStr).trimmed();
                        updateSubProcessXmlTitle(algorithm, titleStr);
                        emit sigAddSubProcessData(m_flowFilePath, targetFilePath);
                    }
                    else
                    {
                        QFileInfo subFInfo(subFilePath);
                        titleStr = subFInfo.baseName();
                        // 插入的是子流程插件
                        emit sigAddSubProcessDataItem(m_flowFilePath, subFilePath, cellId, targetFilePath);
                    }
                    modifySubProcessNodeValue(algorithm, targetFilePath);
                    emit sigUpdatePluginSubProcessFile(cellId.toInt(), targetFilePath, titleStr);
                }
                bool isParallel = checkInsertParallelNode(algorithm, cellId);
                if(isParallel)
                {
                    int branchNum = 2;
                    emit sigCreateParallelBranch(branchNum, cellId);
                    if(branchNum > 2)
                    {
                        QString branchStr = QString("branch=%1").arg(branchNum);
                        updateParallelXmlBranchNum(doc, algorithm, branchStr, branchNum);
                    }
                    else if(branchNum < 2)
                    {
                        if (!multiInsert())
                        {
                            setStatus(Selectable);
                            this->m_iBlockNum = cellId.toInt();
                        }
                        return;
                    }
                }
                QBlock *branch = ip.branch();
                if(branch)
                {
                    makeUndo();
                    QBlock *bl = branch->insertXmlTree(ip.index(), algorithm);
                    if(nullptr == bl) return;
                    bl->m_bSubProcess = isSubProcess;
                    if(m_pActiveBlock)
                    {
                        m_pActiveBlock->m_bSelectAll = false;
                    }
                    m_pActiveBlock = nullptr;

                    emit changed();
                    emit sigInsertNode(bl, m_bIsPaste);
                    if (m_bIsPaste)
                    {
                        m_bIsPaste = false;
                    }
                }
            }
        }

        if (!multiInsert())
        {
            setStatus(Selectable);
        }
    }
}

void QFlowChart::mouseMoveEvent(QMouseEvent *pEvent)
{
    if(status() == Insertion)
    {
        QPoint mp = pEvent->pos();
        QInsertionPoint ip = getNearistPoint(mp.x(), mp.y());
        m_targetPoint = ip;
        repaint();
    }
}

void QFlowChart::mouseDoubleClickEvent(QMouseEvent * event)
{
    if(event->button()==Qt::LeftButton
            && status() == Selectable
            && event->modifiers() == Qt::NoModifier)
    {

        QBlock *block = root()->blockAt(event->x(), event->y());
        if (block)
        {
            emit changed();
            emit editBlock(block);
        }
    }
}

void QFlowChart::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);
    emit sigSizeChange();
}

void QFlowChart::clear()
{
    m_iBlockNum = 3;
    slotDelAllBlocksSelectState();
    m_findTargetBlockLst.clear();
    root()->clear();
    root()->m_hashAttributes.clear();
    root()->setType("algorithm");
    QBlock *branch = new QBlock();
    branch->setType("branch");
    branch->m_bIsBranch = true;
    root()->append(branch);
    branch->setFlowChart(root()->flowChart());

    emit changed();
}

void QFlowChart::realignObjects()
{
    if(root())
    {
        makeBackwardCompatibility();
        root()->adjustSize(zoom());
        root()->adjustPosition(0, 0);
        resize(static_cast<int>(root()->m_dWidth), static_cast<int>(root()->m_dHeight));
        emit changed();
        QWidget::update();
        m_bIsUpdateAerialView = true;
    }
}

void QFlowChart::updateParentBlockSelectedState(QBlock *block)
{
    if(block)
    {
        if(block->m_bSelectAll)
        {
            block->m_bSelectAll = false;
        }
        if(block == root())
        {
            return;
        }
        QBlock *parentBlock = block->m_pParentBlock;
        updateParentBlockSelectedState(parentBlock);
    }
}

void QFlowChart::delCurBlockChildBlockSelectedState(QBlock *block)
{
    QBlock *ro = block;
    for(int i = 0;i < ro->m_lstChildItems.size();i++)
    {
        QBlock* curBlock = ro->m_lstChildItems.at(i);
        if(!curBlock) continue;
        if(!m_findTargetBlockLst.contains(curBlock))
        {
            ro->m_lstChildItems.at(i)->m_bSelectAll = false;
        }
        delCurBlockChildBlockSelectedState(ro->m_lstChildItems.at(i));
    }
}

QSize QFlowChart::sizeHint() const
{
    if (root())
    {
        return QSize(static_cast<int>(root()->m_dWidth), static_cast<int>(root()->m_dHeight));
    }

    return QSize();
}

QBlock *QFlowChart::getChildBlock(QBlock *block, const QString &blockCode, const QString &cellId)
{
    if (!block)
    {
        return nullptr;
    }

    for(auto childBlock  : block->m_lstChildItems)
    {
        if (childBlock)
        {
            QString pcode = childBlock->m_hashAttributes.value("code");
            QString cId = childBlock->m_hashAttributes.value("id");
            if(blockCode == pcode && cellId == cId)
            {
                return childBlock;
            }
        }

        QBlock* pBlock = getChildBlock(childBlock, blockCode, cellId);
        if (pBlock)
        {
            return pBlock;
        }
    }

    return nullptr;
}

void QFlowChart::findBlocksByKeyWord(QBlock *inBlock, const QString &keyStr, const int &searchType)
{
    if(!inBlock) return;
    QList<QBlock *> childBlocks = inBlock->m_lstChildItems;
    for (QBlock *childBlock:childBlocks)
    {
        if(!childBlock) continue;
        childBlock->m_bSelectAll = false;
        bool matchRet = childBlock->getKeywordMatchedResult(keyStr, searchType);
        childBlock->m_bFindActive = matchRet;
        if(matchRet)
        {
            m_findTargetBlockLst.append(childBlock);
        }
        if(childBlock->m_lstChildItems.size() > 0)
        {
            //递归查找
            findBlocksByKeyWord(childBlock, keyStr, searchType);
        }
    }
}

void QFlowChart::updateBlocksReferenceStatus(QBlock *inBlock, QStringList &allCurIdLst, QStringList &allPreIdLst)
{
    if(!inBlock) return;
    QList<QBlock *> childBlocks = inBlock->m_lstChildItems;
    for (QBlock *childBlock:childBlocks)
    {
        if(!childBlock) continue;
        QString curIDStr = childBlock->m_strId.trimmed();
        QString preIDStr = childBlock->m_strPreId.trimmed();

        QList<CVV::Interface::FlowCellParam> cellParamLst = childBlock->m_pluginInfoList;
        for(auto &cellParam:cellParamLst)
        {
            if(cellParam.isSave() != "true")
            {
                continue;
            }
            QString strVal = cellParam.value().trimmed();
            if(strVal.isEmpty())
            {
                continue;
            }
            QString strType = cellParam.type();
            if((0 == strType.compare("String", Qt::CaseInsensitive)) || (0 == strType.compare("QString", Qt::CaseInsensitive)))
            {
                setCellParamReferenceCensus(strVal);
            }
            else if((0 == strType.compare("StringList", Qt::CaseInsensitive)) || (0 == strType.compare("QStringList", Qt::CaseInsensitive)))
            {
                QStringList valLst = strVal.split(',');
                for(auto &subStr:valLst)
                {
                    if(!setCellParamReferenceCensus(subStr))
                    {
                        break;
                    }
                }
            }
        }
        if(!allCurIdLst.contains(curIDStr) && !curIDStr.isEmpty())
        {
            allCurIdLst.append(curIDStr);
        }
        if(!preIDStr.isEmpty())
        {
            QStringList prestrLst = preIDStr.split(',');
            for(QString preId:prestrLst)
            {
                preId = preId.trimmed();
                if(!allPreIdLst.contains(preId))
                {
                    allPreIdLst.append(preId);
                }
            }
        }

        if(childBlock->m_lstChildItems.size() > 0)
        {
            updateBlocksReferenceStatus(childBlock, allCurIdLst, allPreIdLst);
        }
    }
}

 void QFlowChart::updateBlocksReferenceCurBlock(QBlock *inBlock, QString targetStr)
{
     if(nullptr == inBlock) return;
     QList<QBlock *> childBlocks = inBlock->m_lstChildItems;
     for (QBlock *childBlock:childBlocks)
     {
         if(!childBlock) continue;
         bool matchRet = childBlock->getKeywordMatchedResult(targetStr);
         if(matchRet)
         {
             m_referencedIdLst.append(childBlock->m_strId);
         }
         if(childBlock->m_lstChildItems.size() > 0)
         {
             updateBlocksReferenceCurBlock(childBlock, targetStr);
         }
     }
 }

 void QFlowChart::updateBlocksExpandState(QBlock *inBlock, bool isExpand)
 {
    if(nullptr == inBlock) return;
    QList<QBlock *> childBlocks = inBlock->m_lstChildItems;
    for(QBlock *child:childBlocks)
    {
        if(!child) continue;
        child->setBlockVisible(isExpand);
        bool childExpand = true;
        // 判断子节点中是否是容器节点,若是的判断其是否展开,若折叠,就不继续往下遍历
        if(child->isBockType(QFlowEnum::BlockType::Parallel) ||
                child->isBockType(QFlowEnum::BlockType::IF)  ||
                child->isBockType(QFlowEnum::BlockType::Pre) ||
                child->isBockType(QFlowEnum::BlockType::Post)||
                child->isBockType(QFlowEnum::BlockType::For))
        {
            childExpand = child->getBlockExpandState();
        }

        if(!childExpand)
        {
            continue;
        }
        if(child->m_lstChildItems.size() > 0)
        {
            updateBlocksExpandState(child, isExpand);
        }
    }
 }

 bool QFlowChart::setCellParamReferenceCensus(QString &strVal)
 {
     QStringList valLst = strVal.split('.');
     if(3 != valLst.size()) return false;

     QString idStr = valLst[1];
     bool bvlid = false;
     int iId = idStr.toInt(&bvlid);
     if(bvlid)
     {
         int iCount = 1;
         if(m_cellReferencedMap.contains(idStr))
         {
             iCount = m_cellReferencedMap.value(idStr);
             ++iCount;
         }
         m_cellReferencedMap.insert(idStr, iCount);
     }
     return bvlid;
 }

 bool QFlowChart::checkInsertSubProcessNode(QDomElement &domEle, QString &subPath, QString &plugInId)
 {
     bool isSub = false;
     QDomNodeList children = domEle.childNodes();
     int childSize = children.size();
     for(int i = 0; i < childSize && !isSub; ++i)
     {
         if (children.at(i).isElement())
         {
             QDomElement child = children.at(i).toElement();
             QDomNodeList subChildLst = child.childNodes();
             int subSize = subChildLst.size();
             for(int j = 0; j < subSize && !isSub; ++j)
             {
                if(subChildLst.at(j).isElement())
                {
                    QDomElement subChild = subChildLst.at(j).toElement();
                    if(subChild.nodeName() == "subflow")
                    {
                        QDomNamedNodeMap attrs = subChild.attributes();
                        for (int arri = 0; arri < attrs.size(); ++arri)
                        {
                            QDomAttr da = attrs.item(arri).toAttr();
                            QString daName = da.name();
                            if("code" == daName)
                            {
                                QString codeStr = da.value();
                                if("Subprocess" == codeStr)
                                {
                                    isSub = true;
                                }
                            }
                            else if("fileName" == daName)
                            {
                                subPath = da.value();
                            }
                            else if("id" == daName)
                            {
                                plugInId = da.value();
                            }
                        }
                    }
                }
             }
         }
     }
     return isSub;
 }

 bool QFlowChart::checkInsertParallelNode(QDomElement &domEle, QString &plugInId)
 {
     bool isParallel = false;
     QDomNodeList children = domEle.childNodes();
     int childSize = children.size();
     for(int i = 0; i < childSize && !isParallel; ++i)
     {
         if (children.at(i).isElement())
         {
             QDomElement child = children.at(i).toElement();
             QDomNodeList subChildLst = child.childNodes();
             int subSize = subChildLst.size();
             for(int j = 0; j < subSize && !isParallel; ++j)
             {
                if(subChildLst.at(j).isElement())
                {
                    QDomElement subChild = subChildLst.at(j).toElement();
                    if("parallel" == subChild.nodeName())
                    {
                        QDomNamedNodeMap attrs = subChild.attributes();
                        for (int arri = 0; arri < attrs.size(); ++arri)
                        {
                            QDomAttr da = attrs.item(arri).toAttr();
                            QString daName = da.name();
                            if("code" == daName)
                            {
                                QString codeStr = da.value();
                                if("Parallel" == codeStr)
                                {
                                    isParallel = true;
                                }
                            }
                            else if("id" == daName)
                            {
                                plugInId = da.value();
                            }
                        }
                    }
                }
             }
         }
     }
     return isParallel;
 }

 void QFlowChart::modifySubProcessNodeValue(QDomElement &domEle, QString modifyStr)
 {
    QDomNodeList list = domEle.elementsByTagName("branch");
    if(list.size() > 0)
    {
        QDomNode node = list.at(0).firstChild();
        if("subflow" == node.nodeName())
        {
            node.toElement().setAttribute("fileName", modifyStr);
            QDomNode parentNode = list.at(0);
            QDomNode oldNode = parentNode.firstChild();
            parentNode.replaceChild(node, oldNode);
        }
    }
 }

 void QFlowChart::updateSubProcessXmlTitle(QDomElement &domEle, const QString titleStr)
 {
     QDomElement firElement = domEle.firstChildElement();
     QDomElement subChildEle = firElement.firstChildElement("subflow");
     if(subChildEle.isNull()) return;
     subChildEle.setAttribute("title", titleStr);
 }

 void QFlowChart::updateParallelXmlBranchNum(QDomDocument& doc, QDomElement &domEle, const QString numStr, const int iNum)
 {
     QDomElement firElement = domEle.firstChildElement();
     QDomElement subChildEle = firElement.firstChildElement("parallel");
     if(subChildEle.isNull()) return;
     subChildEle.setAttribute("cond", numStr);
     if(iNum > 2)
     {
         for(int addI = 0 ; addI < iNum - 2; addI++)
         {
            QDomElement newEle = doc.createElement("branch");
            subChildEle.appendChild(newEle);
         }
     }
 }

}
}
